package com.sojpt.boot;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.jfinal.aop.Invocation;
import com.jfinal.core.Action;
import com.jfinal.core.ActionHandler;
import com.jfinal.core.ActionReporter;
import com.jfinal.core.Controller;
import com.jfinal.kit.PropKit;
import com.jfinal.render.Render;

@Aspect
@Component
@Order(10)
public class SoJptControllerAspectConfig {

	@Autowired
	private ActiveRecordPluginProperties arpProperties;

	private final static String contextPath = PropKit.use("application.properties").get("server.servlet.context-path");

	/**
	 * *匹配带有 AdminOnlyMethod Annotation的方法
	 */
	@Pointcut("execution(public * com.jfinal.core.Controller+.*(..))")
	public void sojptMethod() {

	}

	@Around("sojptMethod()")
	// synchronized 解决spring cloud (多线程) 环境下报 UT010005: Cannot call
	// getOutputStream(), getWriter() already called 的异常
	public synchronized Object around(ProceedingJoinPoint jp) throws Throwable {

		Object obj = null;
		//long s = System.currentTimeMillis();

		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
				.getRequestAttributes();

		HttpServletRequest request = requestAttributes.getRequest();
		HttpServletResponse response = requestAttributes.getResponse();

		String[] urlPara = { null };
		String target = contextPath == null ? request.getRequestURI()
				: request.getRequestURI().substring(contextPath.length());

		Action action = ActionHandler.actionMapping.getAction(target, urlPara);
		if (action == null) {
			return jp.proceed(jp.getArgs());
		}

		Method method = jp.getTarget().getClass().getMethod("_init_", Action.class, HttpServletRequest.class,
				HttpServletResponse.class, String.class);
		method.invoke(jp.getTarget(), action, request, response, urlPara[0]);

		Controller controller = ActionHandler.controllerFactory.getController(action.getControllerClass());
		if (ActionHandler.injectDependency) {
			com.jfinal.aop.Aop.inject(controller);
		}
		controller._init_(action, request, response, urlPara[0]);

		if (arpProperties.getIsDevMode()) {
			if (ActionReporter.isReportAfterInvocation(request)) {
				obj = new Invocation(action, controller, jp).invoke();
				ActionReporter.report(target, controller, action);
			} else {
				ActionReporter.report(target, controller, action);
				obj = new Invocation(action, controller, jp).invoke();
			}
		} else {
			obj = new Invocation(action, controller, jp).invoke();
		}
		obj = null;
		Render render = (Render) jp.getTarget().getClass().getMethod("getRender").invoke(jp.getTarget());
		if (render == null)
			render = controller.getRender(); // 拦截器的render
		if (render != null) { // controller使用了render方法
			HttpServletRequest request2 = (HttpServletRequest) jp.getTarget().getClass().getMethod("getRequest")
					.invoke(jp.getTarget());
			HttpServletResponse response2 = (HttpServletResponse) jp.getTarget().getClass().getMethod("getResponse")
					.invoke(jp.getTarget());

			render.setContext(request2, response2);

			try {
				render.render();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		//long e = System.currentTimeMillis();
		//System.err.println("耗时: " + (e - s) + " 毫秒");

		return obj;
	}

}